package Network

import (
	"encoding/base64"
	"encoding/json"
	"image"
	_ "image/gif"
	"image/jpeg"
	_ "image/png"
	"logs"
	"net/http"
	"os"
	"strings"
	"time"
	"token"
)

const (
	maxCompressSize    = 10 * (1 << 10) //10k
	minCompressPercent = 10             //10%
)

func getFile(w http.ResponseWriter, req *http.Request) {
	var (
		code     int         = Success
		msg      string      = ""
		result   interface{} = nil
		httpCode int         = http.StatusOK
	)
	defer func() {
		w.WriteHeader(httpCode)
		if httpCode != http.StatusOK {
			writeHTTPResult(w, code, msg, result)
			logs.Print(code, msg)
		}
	}()
	compress := req.FormValue("compress")
	if compress != "" && compress != "true" && compress != "false" {
		httpCode = http.StatusBadRequest
		code = errNotBool
		msg = "compress 应为 true或false"
		return
	}

	httpCode, fileInfo, base64FilePath := Decode(req, compress)
	if httpCode != http.StatusOK {
		code = errNoPermission
		msg = "文件不存在:" + base64FilePath
		return
	}

	Token := req.FormValue("token")
	user, ok := token.GetUser(Token)
	if !ok {
		httpCode = http.StatusForbidden
		code = errNoPermission
		msg = "token 无效"
		return
	}

	//如果接收人或者发送人是自己，直接给
	if user.ID == fileInfo.ReceiverID || user.ID == fileInfo.SenderID {
		httpCode, code, msg = WriteFile(w, req, fileInfo, base64FilePath)
		return
	}

	code, msg = IsGroupID(fileInfo.ReceiverID)
	if code != Success {
		httpCode = http.StatusForbidden
		if code == errInvalidID {
			code = errNoPermission
			msg = "you have no permission to get this file"
		}
		return
	}

	code, msg = IsGroupMember(user.ID, fileInfo.ReceiverID)
	if code != Success {
		httpCode = http.StatusForbidden
		if code == errInvalidID {
			code = errNoPermission
			msg = "you have no permission to get this file"
		}
		return
	}

	httpCode, code, msg = WriteFile(w, req, fileInfo, base64FilePath)
	return

}
func fileExist(path string) bool {
	_, err := os.Stat(path)
	if err != nil {
		return false
	}
	return true
}
func WriteFile(w http.ResponseWriter, req *http.Request, fileInfo *FileInfo, base64FilePath string) (httpCode int, code int, msg string) {
	file, err := os.Open(base64FilePath)
	if err != nil {
		httpCode = http.StatusNotFound
		code = errFileNotFound
		msg = err.Error()
		return
	}
	defer file.Close()
	w.Header().Set("Filename", fileInfo.FileName)
	http.ServeContent(w, req, fileInfo.FileName, time.Time{}, file)
	return http.StatusOK, Success, ""
}

func Decode(req *http.Request, compress string) (httpCode int, fileInfo *FileInfo, base64FilePath string) {
	fileInfo = new(FileInfo)
	URL := strings.Split(req.URL.Path, "/")
	if len(URL) == 0 {
		return http.StatusNotFound, nil, "URL为空！"
	}
	base64FileName := URL[len(URL)-1]
	fileName, err := base64.StdEncoding.DecodeString(base64FileName)
	if err != nil {
		return http.StatusBadRequest, nil, err.Error()
	}
	err = json.Unmarshal(fileName, fileInfo)
	if err != nil {
		return http.StatusForbidden, nil, err.Error()
	}
	if compress == "false" || fileInfo.FileType != "image" {
		return http.StatusOK, fileInfo, privateFileDir + "/" + fileInfo.FileType + "/" + base64FileName
	}
	httpCode, base64FilePath = Compress(base64FileName, fileInfo)
	if httpCode != http.StatusOK {
		return httpCode, nil, base64FilePath
	}
	return httpCode, fileInfo, base64FilePath
}

func Compress(base64FileName string, fileInfo *FileInfo) (httpCode int, base64FilePath string) {
	base64FilePath = privateFileDir + "/compress_image/" + base64FileName
	if fileExist(base64FilePath) {
		return http.StatusOK, base64FilePath
	}
	file, err := os.Open(privateFileDir + "/" + fileInfo.FileType + "/" + base64FileName)
	if err != nil {
		return http.StatusNotFound, err.Error()
	}
	defer file.Close()
	stat, err := file.Stat()
	if err != nil {
		return http.StatusInternalServerError, err.Error()
	}
	size := stat.Size()
	persent := 100
	if size > maxCompressSize {
		persent = (int)(maxCompressSize / size)
	}
	if persent < 10 {
		persent = 10
	}
	img, _, err := image.Decode(file)
	if err != nil {
		return http.StatusConflict, err.Error()
	}
	compress_img, err := os.Create(base64FilePath)
	if err != nil {
		return http.StatusConflict, err.Error()
	}
	defer compress_img.Close()
	err = jpeg.Encode(compress_img, img, &jpeg.Options{persent})
	if err != nil {
		os.Remove(base64FilePath)
		return http.StatusInternalServerError, err.Error()
	}
	return http.StatusOK, base64FilePath
}
